package cn.edu.laud.sany.generatedata;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import cn.edu.laud.sany.types.ImportProcess;
import cn.edu.laud.sany.utils.Config;
import cn.edu.laud.sany.utils.MyLog;

public class SanyGenerateData
{
	public static int thread = 1;
	public static Integer[] paraArray;
	public static HashMap<Integer, SanyParaInfo> paraMap;
	public static HashMap<String, Long> equipMap = new HashMap<String, Long>();
	public static HashMap<String, Long> equipMapGen = new HashMap<String, Long>();
	public static String csvFolder = "";
	public static String csvOutputFolder = "";
	public static String cfsFile = "";
	public static String logFileFolder = "log";
	public static String logFileName = "mylogtest.txt";
	public static long oneFileSize = 10000000;
	public static int readDataLimit = 100000000;

	private static MyLog logger;
	private static ConcurrentLinkedQueue<ImportProcess> filequeue;

	/**
	 * @param args
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	public static void main(String[] args) throws ClassNotFoundException,
			SQLException, IOException
	{
		initLaUDMyLog();
		doMain(args);
	}

	public static String getLogFilePath()
	{
		return (logFileFolder + "/" + logFileName);
	}

	protected static void initLaUDMyLog()
	{
		File logFolderFile = new File(logFileFolder);
		if (logFolderFile.exists() == false)
		{
			logFolderFile.mkdir();
		}
		logger = MyLog.getMyLog(getLogFilePath(), true);
	}

	protected static void doMain(String[] args) throws ClassNotFoundException,
			SQLException, IOException
	{
		if (args.length % 2 == 1 || args.length < 1)
		{
			System.err.println(Config.GenerateDataCommandHelpString);
			return;
		}

		try
		{
			parseParams(args);
		}
		catch (Exception e)
		{
			System.err.println(Config.GenerateDataCommandHelpString);
			return;
		}

		// test csv and cfs files
		if (testCsvFoler() == false)
		{
			System.err.println("can not find csv folder");
			return;
		}
		if (testCfFile() == false)
		{
			System.err.println("can not find CFs file");
			return;
		}
		if (getCFNames() == false)
		{
			System.err.println("can not read CFs correctly");
			return;
		}
		logger.info("generate data start...");

		try
		{
			initQueue();
		}
		catch (Exception e)
		{
			System.err.println("init file queue failed: " + e.getMessage());
			return;
		}

		logger.info("create threads to read ori data...");

		BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
		ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 100,
				TimeUnit.DAYS, queue);

		for (int i = 0; i < thread; i++)
		{
			executor.execute(new SanyCSVReader(i));
		}
		executor.shutdown();
		try
		{
			executor.awaitTermination(100, TimeUnit.DAYS);
		}
		catch (InterruptedException e1)
		{
			logger.error("main thread interrupted while waiting "
					+ e1.getMessage());
		}

		int factor = SanyCSVReader.count / 100000;
		if (factor == 0)
		{
			factor = 1;
		}
		Iterator<Entry<String, Long>> iter = equipMap.entrySet().iterator();
		while (iter.hasNext())
		{
			Entry<String, Long> item = iter.next();
			long value = item.getValue() / factor;
			if (value == 0)
			{
				value = 1;
			}
			equipMapGen.put(item.getKey(), value);
		}
		logger.info("create threads to generate new data...");

		BlockingQueue<Runnable> queue1 = new LinkedBlockingQueue<Runnable>();
		ThreadPoolExecutor executor1 = new ThreadPoolExecutor(10, 10, 100,
				TimeUnit.DAYS, queue1);

		for (int i = 0; i < thread; i++)
		{
			executor1.execute(new SanyCSVWriter(i));
		}
		executor.shutdown();
		try
		{
			executor.awaitTermination(100, TimeUnit.DAYS);
		}
		catch (InterruptedException e1)
		{
			logger.error("main thread interrupted while waiting "
					+ e1.getMessage());
		}

		logger.info("generate data finish.");
	}

	protected static void parseParams(String[] args)
	{
		for (int i = 0; i < args.length; i += 2)
		{
			if (args[i].equals("--thread"))
			{
				thread = Integer.valueOf(args[i + 1]);
			}
			else if (args[i].equals("--csvpath"))
			{
				csvFolder = args[i + 1];
			}
			else if (args[i].equals("--cfsfile"))
			{
				cfsFile = args[i + 1];
			}
			else if (args[i].equals("--filesize"))
			{
				oneFileSize = Integer.valueOf(args[i + 1]);
			}
			else if (args[i].equals("--readlimit"))
			{
				readDataLimit = Integer.valueOf(args[i + 1]);
			}
		}
		logger.info("thread = " + thread);
		logger.info("csv path = " + csvFolder);
		logger.info("cfs file = " + cfsFile);
		logger.info("file size = " + oneFileSize);
		logger.info("read limit = " + readDataLimit);
	}

	protected static boolean getCFNames()
	{
		paraMap = new HashMap<Integer, SanyParaInfo>();
		boolean flag = true;
		File file = new File(cfsFile);
		BufferedReader bReader = null;
		String paraIdString = null;
		ArrayList<Integer> cfList = new ArrayList<Integer>();
		try
		{
			bReader = new BufferedReader(new FileReader(file));
			while ((paraIdString = bReader.readLine()) != null)
			{
				paraIdString = paraIdString.trim();
				if (paraIdString.equals(""))
				{
					continue;
				}
				int paraId = Integer.valueOf(paraIdString);
				cfList.add(paraId);
				paraMap.put(paraId, new SanyParaInfo());
			}

		}
		catch (IOException e1)
		{
			flag = false;
			logger.error("can not open cf file");
		}
		catch (NumberFormatException e2)
		{
			flag = false;
			logger.error("cf file contains invalid integer");
		}
		finally
		{
			if (flag == false)
			{
				logger.info("get cfs failed!");
			}
			try
			{
				bReader.close();
			}
			catch (IOException e)
			{
				logger.info(e.getMessage());
			}
		}
		if (flag == true)
		{
			paraArray = cfList.toArray(new Integer[0]);
		}
		return flag;
	}

	protected static boolean testCsvFoler()
	{
		try
		{
			File file = new File(csvFolder);
			if (file.exists())
			{
				csvOutputFolder = file.getAbsolutePath() + "_Output";
				File file1 = new File(csvOutputFolder);
				if (!file1.exists())
				{
					file1.mkdir();
				}
				return true;
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		return false;
	}

	protected static boolean testCfFile()
	{
		try
		{
			File file = new File(cfsFile);
			if (file.exists())
			{
				return true;
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		return false;
	}

	protected static void dealwithRowData(List<RowData> rowList)
	{
		for (RowData rowData : rowList)
		{
			SanyParaInfo info;
			if (paraMap.containsKey(rowData.paraId))
			{
				info = paraMap.get(rowData.paraId);
			}
			else
			{
				info = new SanyParaInfo();
				paraMap.put(rowData.paraId, info);
			}
			if (info.startTime == 0
					|| rowData.localTime.getTime() < info.startTime)
			{
				info.setStart(rowData.localTime);
			}
			if (info.endTime == 0 || rowData.localTime.getTime() > info.endTime)
			{
				info.setEnd(rowData.localTime);
			}
			if (!info.values.contains(rowData.paravalue))
			{
				info.values.add(rowData.paravalue);
			}
			
			if (equipMap.containsKey(rowData.equipCode))
			{
				long count = equipMap.get(rowData.equipCode) + 1;
				equipMap.put(rowData.equipCode, count);
			}
			else
			{
				equipMap.put(rowData.equipCode, 1L);
			}
		}
		rowList.clear();
	}

	private static boolean initQueue()
	{
		filequeue = new ConcurrentLinkedQueue<ImportProcess>();
		try
		{
			File file = new File(csvFolder);
			File[] files = file.listFiles(new FilenameFilter()
			{
				@Override
				public boolean accept(File dir, String name)
				{
					if (!name.endsWith("csv"))
						return false;
					else
						return true;
				}
			});
			// 防止文件正在拷贝
			long size[] = new long[files.length];
			for (int i = 0; i < files.length; i++)
			{
				size[i] = files[i].length();
			}
			try
			{
				Thread.sleep(2000);
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
			for (int i = 0; i < files.length; i++)
			{
				if (size[i] == files[i].length())
				{
					// 2s没变，认为没有拷贝
					String fileName = files[i].getAbsolutePath();
					ImportProcess process = new ImportProcess(fileName, 0, 0);
					filequeue.add(process);
				}
			}
			return true;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return false;
		}
	}

	public static File getAvailableSource()
	{
		synchronized (filequeue)
		{
			if (filequeue.size() > 0)
			{
				ImportProcess process = filequeue.poll();
				process.status = 1;
				process.isImporting = true;
				File file = new File(process.name);
				return file;
			}
			else
			{
				return null;
			}
		}

	}

}
